require(tidyverse)
Loading required package: tidyverse
Registered S3 methods overwritten by 'dbplyr':
method from
print.tbl_lazy
print.tbl_sql
── Attaching packages ─────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.1 ──
✓ ggplot2 3.3.3 ✓ purrr 0.3.4
✓ tibble 3.1.0 ✓ dplyr 1.0.5
✓ tidyr 1.1.3 ✓ stringr 1.4.0
✓ readr 2.0.1 ✓ forcats 0.5.1
── Conflicts ────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag() masks stats::lag()
require(geosphere)
Loading required package: geosphere
require(rvest)
Loading required package: rvest
Attaching package: ‘rvest’
The following object is masked from ‘package:readr’:
guess_encoding
require(dplyr)
#datos <- read.csv('aterrizajes-y-despegues-registrados-por-eana-2020.csv', sep=";", header=T)
datos <- read.csv('202109-informe-ministerio.csv', sep=";", header=T, encoding = "UTF-8")
# De factor a caracter
datos <- datos %>%
mutate(across(everything(), as.character))
datos
Visualizamos los datos sin datos faltantes y solo del tipo de nuestro interés
datos <- datos %>%
filter(Aeronave != 0,
Aeropuerto != Origen...Destino,
Aerolinea.Nombre != "0",
Clasificación.Vuelo != "Inter")
datos
NA
Vemos que los datos ordenados por fecha y hora, comienzan con arribos de vuelos que despegaron en el día anterior al primero de la tabla, por lo que los borramos.
datos <- datos %>%
slice_tail(n=nrow(datos)-4)
datos
NA
Vamos a necesitar las coordenadas de cada aeropuerto.
Observación: Cada vuelo aparece dos veces en la base de datos, una como despegue, y otro como atterizaje. Dado que contienen la misma información (para este ejercicio), podemos quedarnos solo con los despegues.
Vamos a necesitar unir la tabla de aeropuertos con sus coordenadas a la tabla de vuelos, para poder calcular la distancia entre los mismos.
aereo <- read.csv('Tabla aeropuertos.csv', sep=",", header=T, encoding = "UTF-8")
# De factor a caracter
aereo <- aereo %>%
mutate(across(everything(), as.character))
aereo
Agregamos columnas de coordenadas y filtramos columnas que no necesitamos
datos_distancia <- datos %>%
# Agregamos coordenadas de aeropuerto en columna Aeropuerto
left_join(aereo, by = c( "Aeropuerto" = "ana" ), suffix = c("", ".extra")) %>%
rename(latitud_o=x, longitud_o=y) %>%
# Agregamos coordenadas de aeropuerto en columna Origen...Destino
left_join(aereo, by = c( "Origen...Destino" = "ana" ), suffix = c("", ".extra")) %>%
rename(latitud_d=x, longitud_d=y) %>%
# Filtramos columnas no relevantes o repetidas
select(-one_of(c("Calidad.dato", "ose", "iko", "ita", "thr", "fuc",
"ose.extra", "iko.extra", "ita.extra", "thr.extra", "fuc.extra",
"id.extra", "cpr.extra", "pais.extra", "nam.extra", "fna.extra", "nom_ciudad.extra")))
datos_distancia
Calculamos distancia para cada fila
datos_distancia <- datos_distancia %>%
rowwise() %>%
mutate(Distancia.recorrida.km = distHaversine(p1 = (1/1000) * c(as.numeric(latitud_o), as.numeric(longitud_o)),
p2 = (1/1000) * c(as.numeric(latitud_d), as.numeric(longitud_d))))
datos_distancia
Para calcular la velocidad necesitamos el tiempo de vuelo, y por lo tanto, la hora de despegue y la de aterrizaje.
Primero, visualizamos los datos de una manera ordenada aproximada
datos.velocidades <- datos_distancia %>%
mutate(Fecha.Hora = strptime(x = paste(Fecha, Hora.UTC),
format = "%d/%m/%Y %H:%M"), .before=Fecha) %>%
arrange(Aeronave, Fecha.Hora)
datos.velocidades
Elegimos ignorar este algoritmo pues no solo es lento al ejecutarse, sino que luego de ejecutarlo, RStudio ejecuta todo con pausas y delays, lo que vuelve muy poco dinámico el análisis de datos.
# Para mostrar progreso del algoritmo
#install.packages("svMisc")
#require(svMisc)
# Como funcion para evitar su ejecución
iterativo <- function(){
HORAS.MAX <- 10
DEBUGGING <- FALSE
NUM.DATA <- as.integer(nrow(datos.velocidades) / 10)
set.seed(42)
if (!DEBUGGING){
num.filas <- nrow(datos.velocidades)
} else {
num.filas <- NUM.DATA
datos.velocidades <- data.frame(datos.velocidades) %>% slice_sample(n=NUM.DATA)
}
datos.velocidades$"Velocidad" <- rep(NA, num.filas)
datos.velocidades$"Tiempo.vuelo" <- rep(NA, num.filas)
for(i in 1:(num.filas-1))
{
progress(i, max.value = (num.filas-1), )
seguir.buscando <- TRUE
j <- i + 1
# Solo busco match para cada despegue
if(datos.velocidades[[i, "Tipo.de.Movimiento"]] == "Despegue")
{
while (seguir.buscando && j <= nrow(datos.velocidades))
{
# Calculo tiempo de vuelo entre cada 2 filas
# No hay vuelos mayores a 10 horas, dejo de buscar para esta fila i,
# la dejo como NA para filtrar luego, y paso al siguiente despegue
tiempo.vuelo <- as.numeric(datos.velocidades[[j, "Fecha.Hora"]] - datos.velocidades[[i, "Fecha.Hora"]], units="hours")
# Como los tengo ordenados por fecha, y luego por modelo de avión, puedo
# salir del loop interno al ver un aterrizaje con otro modelo de avión
# (pues todos los siguientes son tambien distintos al de origen).
distinta.aeronave <- datos.velocidades[[j, "Aeronave"]] != datos.velocidades[[i, "Aeronave"]]
if(tiempo.vuelo > HORAS.MAX | distinta.aeronave){
# Dejo de buscar match, y depegue en fila i queda incompleto (y descartado)
seguir.buscando <- FALSE
}
else
{
es.match <- is.na(datos.velocidades[[j, "Velocidad"]] &&
datos.velocidades[[j, "Tipo.de.Movimiento"]] == "Aterrizaje" &&
datos.velocidades[[j, "Origen...Destino"]] == datos.velocidades[[i, "Aeropuerto"]] &&
datos.velocidades[[j, "Aeropuerto"]] == datos.velocidades[[i, "Origen...Destino"]])
if(es.match)
{
# Coincidencia de 2 filas, calculo velocidad y paso a siguiente despegue
velocidad.media <- datos.velocidades[[i, "Distancia.recorrida.km"]] / tiempo.vuelo
datos.velocidades$Velocidad[i] <- velocidad.media
datos.velocidades$Velocidad[j] <- velocidad.media
datos.velocidades$Tiempo.vuelo[i] <- tiempo.vuelo
datos.velocidades$Tiempo.vuelo[j] <- tiempo.vuelo
seguir.buscando <- FALSE
}
# Paso a siguiente aterrizaje
j <- j + 1
}
}
}
}
}
# dividimos en despegues y aterrizajes
despegues <- datos.velocidades[datos.velocidades$Tipo.de.Movimiento == 'Despegue',]
aterrizajes <- datos.velocidades[datos.velocidades$Tipo.de.Movimiento == 'Aterrizaje',]
datos.velocidades <- datos.matched %>% mutate(Velocidad = Distancia.recorrida.km.x / Tiempo.vuelo)
datos.velocidades
datos.velocidades %>%
filter(Aeropuerto == 'AER') %>%
group_by(Origen...Destino) %>%
mutate(count=n()) %>%
filter(count>300) %>%
ggplot(aes(x = Tiempo.vuelo)) +
geom_histogram(fill = "steelblue", colour = "black") +
facet_grid(Origen...Destino ~ .)
Observamos que el tiempo medio del histograma de Usuaia y el de El Calafate está por encima de los otros, lo cual se condice con la distancia mayor que se debe recorrer
Analizamos la cantidad de viajes por aerolínea.
frec.aerolinea <- datos.velocidades %>%
group_by(Aerolinea.Nombre) %>%
summarise(Frecuencia=n()) %>%
arrange(desc(Frecuencia))
frec.aerolinea
barplot(frec.aerolinea$Frecuencia, names.arg=frec.aerolinea$Aerolinea.Nombre, las=2, cex.names = 0.5, col="steelblue")
Como se ve en el barplot, Aerolineas Argentinas tiene la mayor cantidad de vuelos realizados, lo cual es esperable dado que estamos visualizando vuelos nacionales.
De entre todos los modelos de avión, vemos si hay alguno más frecuente que otros.
frec.aeronave <- datos.velocidades %>%
group_by(Aeronave) %>%
summarise(Frecuencia = n(), Velocidad.mediana = median(Velocidad)) %>%
arrange(desc(Frecuencia))
frec.aeronave
plot(log(frec.aeronave$Frecuencia), frec.aeronave$Velocidad.mediana, col="steelblue", pch=20)
points(log(frec.aeronave$Frecuencia[frec.aeronave$Aeronave == "EMB-ERJ190100IGW"]), frec.aeronave$Velocidad.mediana[frec.aeronave$Aeronave == "EMB-ERJ190100IGW"], col="red", pch=20, cex=1.5)
Vemos que el avión más frecuente (destacado en rojo), está cerca de los más rápidos. Podemos ubicarlo en un boxplot de frecuencias para comparar mejor sobre el resto de los modelos de avión:
boxplot(frec.aeronave$Velocidad.mediana)
abline(h=frec.aeronave$Velocidad.mediana[frec.aeronave$Aeronave == "EMB-ERJ190100IGW"], col="red")
Con esto observamos que existen modelos de avión con velocidades superiores al del más usado, lo cual indicaría que existe otra variable que incentiva su uso (por ejemplo: capacidad, mantenimiento, costo relativo, etc).
Visualizando la frecuencia de uso de cada modelo, podemos ver como el modelo más usado está muy por encima de los demás, y para cada modelo de avión, se observa un decaimiento similar a una exponencial:
barplot(frec.aeronave$Frecuencia, names.arg=frec.aeronave$Aeronave, las=2, cex.names = 0.5, col="steelblue")
Esto se condice con el hecho de que la aerolínea con más vuelos es Aerolineas Argentina, la cual es la única que usa el modelo de avión EMB-ERJ190100IGW en la gran mayoría de sus vuelos, como podemos ver con el siguiente código:
frec.aeronave.AA <- datos.velocidades %>%
filter(Aerolinea.Nombre == "AEROLINEAS ARGENTINAS SA") %>%
group_by(Aeronave) %>%
summarise(Frecuencia=n()) %>%
arrange(desc(Frecuencia))
frec.aeronave.AA
barplot(frec.aeronave.AA$Frecuencia, names.arg=frec.aeronave.AA$Aeronave, las=2, cex.names = 0.5, col="steelblue")
Dado que a pesar de que el modelo EMB-ERJ190100IGW no es el más veloz, es el predominamente más usado por sobre los otros modelos de la empresa, lo cual es un indicio de que probablemente haya un motivo por el cual es utilizado.
Podemos ver la proporción relativa de este modelo sobre el total de vuelos:
frec.modelo <- frec.aeronave.AA[frec.aeronave.AA$Aeronave=="EMB-ERJ190100IGW", "Frecuencia"]
frec.total <- sum(frec.aeronave.AA$Frecuencia)
prop.modelo <- frec.modelo / frec.total
prop.modelo
Vemos que esa proporción es del 45%.
A pesar de que es el modelo más usado, más de la mitad de los vuelos son realizados con otros modelos, algo que nos parece anti-intuitivo viendo solo el barplot de frecuencias.
Otro enfoque que podemos tomar, es comparar todos los modelos de todas las aerolíneas con una matriz de correlaciones:
datos.velocidades %>%
select(Aeronave, Aerolinea.Nombre) %>%
#group_by(Aeronave, Aerolinea.Nombre) %>%
group_by(Aerolinea.Nombre) %>%
# La frecuencia se calcula sobre las Aeronaves y las Aerolineas
add_count(Aeronave) %>%
rename(Frecuencia=n) %>%
ungroup() %>%
distinct() %>%
#summarise(Frecuencia=n(), .groups = "drop_last") %>%
arrange(Aeronave) %>%
ggplot(aes(x=Aeronave, y=Aerolinea.Nombre, fill=Frecuencia)) +
geom_tile(color = "white")+
theme_minimal() +
theme(axis.text.x = element_text(angle = 90, vjust = 1,
size = 5, hjust = 1))
A partir de esta matriz, podemos ver que Aerolineas Argentinas tiene la mayor diversidad de modelos de aeronaves (23), mientras las otras aerolinas tienen entre 1 y 4 modelos distintos.
Además, los modelos usados por Aerolineas Argentinas no suelen ser usados por otras aerolineas.
datos.velocidades %>%
filter(Aerolinea.Nombre == "AEROLINEAS ARGENTINAS SA") %>%
select(Aeronave, Origen...Destino) %>%
# La frecuencia se calcula sobre las Aeronaves y los Destinos
group_by(Origen...Destino) %>%
add_count(Aeronave) %>%
rename(Frecuencia=n) %>%
ungroup() %>%
distinct() %>%
# Cambiando frecuencia en arrange por origen...destino cambian las frecuencias
# Qué pasa con el color gris?
#arrange(Origen...Destino) %>%
ggplot(aes(x=Aeronave, y=Origen...Destino, fill=Frecuencia)) +
geom_tile(color = "white") +
theme_minimal() +
scale_fill_gradient(low = "blue", high = "red", limit = c(1,2923), space = "Lab") +
theme(axis.text.x = element_text(angle = 90, vjust = 1,
size = 7, hjust = 1),
axis.text.y = element_text(size = 7))
Observamos que el modelo de avión más usado (EMB-ERJ190100IGW) hace viajes a todos los destinos.
Tambien vemos que los modelos BO-73785F y BO-73786J solo viajan a Salta.
El único modelo que va a Viedma es EMB-ERJ190100IGW
Analizamos ahora a qué destinos hace vuelos cada aerolinea
datos.velocidades %>%
#filter(Aerolinea.Nombre == "AEROLINEAS ARGENTINAS SA") %>%
select(Aerolinea.Nombre, Origen...Destino) %>%
group_by(Aerolinea.Nombre) %>%
# La frecuencia se calcula sobre las Aeronaves y los Destinos
#group_by(Origen...Destino) %>%
add_count(Origen...Destino) %>%
rename(Frecuencia=n) %>%
ungroup() %>%
distinct() %>%
arrange(Frecuencia) %>%
ggplot(aes(x=Aerolinea.Nombre, y=Origen...Destino, fill=Frecuencia)) +
geom_tile(color = "white") +
theme_minimal() +
scale_fill_gradient(low = "blue", high = "red", limit = c(1,6500), space = "Lab") +
theme(axis.text.x = element_text(angle = 75, vjust = 1,
size = 5, hjust = 1),
axis.text.y = element_text(size = 5))
Algunas particularidades que podemos observar:
Hay varias aerolineas que tienen muchos destinos (columnas casi completas) y otras que llegan a tener muy pocas (solo 4 o 5).
Viendo los agujeros de estas columnas, Baires FLY tiene 6, American JET tiene 7, y Aerolíneas Argentinas tiene 8, lo que nos muestra que son las que más destinos tienen.
Aerolíneas con único destino:
Suponemos que esto sucede pues son destino relativamente cercanos para realizar las prácticas de vuelo.
Destinos con únicas aerolíneas:
vel.aeronave <- datos.velocidades %>%
group_by(Aeronave) %>%
mutate(Vel.mediana = median(Velocidad)) %>%
arrange(Vel.mediana)
vel.aeronave
Analizamos la velocidad de los vuelos de Ezeiza a Bariloche y viceversa para estimar el efecto de las corrientes de chorro
datos.EZE.BAR <- datos.velocidades %>%
filter(Aeropuerto == "EZE", Origen...Destino=="BAR") %>%
select(Velocidad) %>%
# Filtramos outliers
filter(Velocidad < median(Velocidad) + median(Velocidad) / 4 &
Velocidad > median(Velocidad) - median(Velocidad) / 4 )
datos.BAR.EZE <- datos.velocidades %>%
filter(Aeropuerto == "BAR", Origen...Destino=="EZE") %>%
select(Velocidad) %>%
# Filtramos outliers
filter(Velocidad < median(Velocidad) + median(Velocidad) / 4 &
Velocidad > median(Velocidad) - median(Velocidad) / 4 )
n.dif <- length(datos.EZE.BAR$Velocidad) - length(datos.BAR.EZE$Velocidad)
tabla.horizontal <- data.frame(Velocidad.ida=datos.EZE.BAR$Velocidad,
Velocidad.vuelta=c(datos.BAR.EZE$Velocidad, rep(NA, n.dif)))
tabla.horizontal %>%
gather() %>%
ggplot(aes(x=value, fill=key)) +
geom_histogram(position="identity") +
ggtitle("Velocidades Ezeiza-Bariloche\nIda vs Vuelta") +
xlab("Velocidad (km/h)") +
ylab("Frecuencia relativa")
Podemos ver como hay una gran diferencia entre la velocidad de ida y la velocidad de vuelta entre los distintos viajes de Ezeiza Bariloche, con los de vuelta notablemente más rápidos.
Esto nos ayuda a pensar el efecto de las corrientes de chorro afectando el recorrido de los vuelos (si la corriente va a favor o en contra del desplazamiento, la velocidad se verá afectada).
Podemos observar que hay muy pocos pasajeros viajando entre las 4 y 6 de la mañana.
Tambien vemos que la mayoría de los vuelos tienen menos de 100 pasajeros, y que hay un pico de más de 100 a las 13, 18 y 19hs, por lo que creemos que son los horarios preferidos por los viajeros.